/*
 * Copyright (c) 2010, Yawning <yawninglol at gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   * Neither the name of the Mew Developers nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package yawning.mew;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Properties;


import yawning.mew.GeneticOptimizer.Optimizer;
import yawning.mew.GeneticOptimizer.Optimizer.CandidateStat;
import yawning.mew.ProcEffect.Effect;
import yawning.mew.Report.Stat;
import yawning.mew.character.Clazz;
import yawning.mew.character.PropertiesToonBuilder;
import yawning.mew.character.PropertiesToonBuilder.Property;
import yawning.mew.character.Race;
import yawning.mew.character.StatLogic;
import yawning.mew.character.Toon;
import yawning.mew.sim.Simulation;
import yawning.mew.target.Target;

/**
 * Mew Command Line Test Harness.
 *
 * @author Yawning <yawninglol at gmail.com>
 */
public class MewCommandLine implements MewView {
    public Mew mew = null;
    private boolean shouldPrintLog = false;
    private boolean mShouldGenerateRSV = false;
    private boolean mShouldOptimize = true;

    private PropertiesBase mConfig;

    public void onLog(String s) {
        if (shouldPrintLog == true) {
            System.out.println(s);
        }
    }

    public void onWarn(String s) {
        System.out.println("WARNING: " + s);
    }

    public void onError(String s) {
        System.out.println("ERROR: " + s);
    }

    public void onIteration(int iter, int maxIter) {
    	// Nothing to do.
    }

    /**
     * Loads the required parameters from a file.
     *
     */
    public boolean loadFromFile(String path) {
        Properties props = new Properties();

        try {
            props.load(new FileInputStream(path));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

		// Tooltip/Armory Attack Power includes Strength and Aggression, subtract that now.
        if (props.getProperty(Property.TALENTSPEC.getKey()).equals("Feral Combat")) {
			if (props.getProperty(Property.ARMORSPEC.getKey()).equals("true")) {
				int ap = Integer.parseInt(props.getProperty("AttackPower"));
				ap = (int) Math.floor((double) ap / 125 * 100); // Aggression: 1.25x AP
				int strAp = (Integer.parseInt(props.getProperty("Strength")) - 10) * 1; // Str -> 1 AP per, past the first 10.
				props.setProperty("AttackPower", Integer.toString(ap - strAp));
			}
        } else if (props.getProperty(Property.TALENTSPEC.getKey()).equals("Protection")) {
        	// Protection as in warriors.  Fuck paladins.
        	int ap = Integer.parseInt(props.getProperty("AttackPower"));
        	int strAp = (Integer.parseInt(props.getProperty("Strength")) - 10) * 2;
        	props.setProperty("AttackPower", Integer.toString(ap - strAp));

        	int sta = Integer.parseInt(props.getProperty("Stamina"));
        	int realSta = (int) Math.round((double) sta / 1.15 / ((props.getProperty(Property.ARMORSPEC.getKey()).equals("true")) ? 1.05 : 1));
        	props.setProperty("Stamina", Integer.toString(realSta));

        	// Mother fucking armory includes parry from str in parry rating.
    		StatLogic statLogic = StatLogic.get(Integer.parseInt(props.getProperty("Level")), Clazz.WARRIOR);
        	Race race = Race.get(props.getProperty("Race"));
        	int parry = Integer.parseInt(props.getProperty("ParryRating"));
        	int strParry = (int) Math.floor((double)(Integer.parseInt(props.getProperty("Strength")) - statLogic.getBaseStrength(race)) * 0.27);
        	props.setProperty("ParryRating", Integer.toString(parry - strParry));
        }

		// Tooltip Armor includes bonus armor / metagem, subtract that now.
		int armor = Integer.parseInt(props.getProperty("Armor", "0"));
		int bonusArmor = Integer.parseInt(props.getProperty("BonusArmor", "0"));
		if (armor > 0) {
			double armorMult = 1.0;
			armorMult *= (props.getProperty("MetaGem").equals("Austere")) ? 1.02 : 1;
			if (props.getProperty(Property.TALENTSPEC.getKey()).equals("Protection")) {
				int toughness = Integer.parseInt(props.getProperty("Talent.Toughness", "0"));
				double toughnessMult = toughness * 0.03 + ((toughness == 3) ? 0.01 : 0);
				armorMult *= 1.0 + toughnessMult;
			}
			armor -= bonusArmor;
			armor /= armorMult;
			props.setProperty("Armor", Integer.toString(armor));
		}

        mConfig = new PropertiesBase(props);
        System.out.println(mConfig.toString());

        // XXX: Validate our options here.

        // Load in the simulator strategy if specified.
        String stratFile = props.getProperty("Simulator.Strategy");
        if (stratFile != null) {
        	String stratBody = readSimStrat(stratFile);
        	if (stratBody != null) {
        		props.setProperty("Simulator.Strategy", stratBody);
        	}
        }

        // Load the test procs.
        loadTestProcs();

        return true;
    }

    /**
     * Read the strategy in from the specified file.
     */
    private String readSimStrat(String fileName) {
    	StringBuilder strat = new StringBuilder();

    	try {
    		BufferedReader reader = new BufferedReader(new FileReader(fileName));

    		try {
    			String line = null;
    			while ((line = reader.readLine()) != null) {
    				strat.append(line);
    				strat.append("\n");
    			}
    		} finally {
    			reader.close();
    		}
    	} catch (IOException e) {
    		e.printStackTrace();
    		return null;
    	}

    	return strat.toString();
    }

    /**
     * Populate our backing store with procs that my beta copy has for testing.
     */
    private void loadTestProcs() {
    	Procs procs = Procs.getInstance();
        ProcEffect p;

        // Items
        p = new ProcEffect();
        p.name = "Vial of Shadows (384)";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 0.15;
		p.buffCooldown = 25;
        p.set(Effect.PHYSICAL_DAMAGE, 13382);
        procs.registerProcByItemID(77979, p);

    	p = new ProcEffect();
    	p.name = "Matrix Restabilizer (397)";
    	p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
    	p.rate = 0.15;
    	p.buffCooldown = 105;
    	p.buffDuration = 30;
    	p.set(Effect.CRIT_RATING, 1834);
    	p.set(Effect.HASTE_RATING, 1834);
    	p.set(Effect.MASTERY_RATING, 1834);
    	p.set(Effect.SPELL_ID, 69150);
    	procs.registerProcByItemID(69150, p);

    	p = new ProcEffect();
		p.name = "Kiril, Fury of Beasts (403)";
    	p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
    	p.rate = 0.15;
    	p.buffCooldown = 55;
    	p.buffDuration = 20;
    	p.set(Effect.AGILITY, 107);
    	p.set(Effect.SPELL_ID, 77194);
    	procs.registerProcByItemID(77194, p);

		p = new ProcEffect();
        p.name = "Fluid Death";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 1.0;
        p.buffStackMax = 10;
        p.buffDuration = 15;
        p.set(Effect.AGILITY, 38);
        procs.registerProcByItemID(58181, p);

		p = new ProcEffect();
        p.name = "Unheeded Warning";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 0.10;
        p.buffDuration = 10;
        p.buffCooldown = 50;
        p.set(Effect.ATTACK_POWER, 1926);
        procs.registerProcByItemID(59520, p);

		p = new ProcEffect();
        p.name = "Tia's Grace (346)";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 1.0;
        p.buffStackMax = 10;
        p.buffDuration = 15;
        p.set(Effect.AGILITY, 34);
        procs.registerProcByItemID(56394, p);

        p = new ProcEffect();
        p.name = "Prestor's Talisman of Machination (359)";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 0.10;
        p.buffDuration = 15;
        p.buffCooldown = 75;
        p.set(Effect.HASTE_RATING, 1926);
        procs.registerProcByItemID(59441, p);

        p = new ProcEffect();
        p.name = "Essence of the Cyclone (372)";
        p.triggers = EnumSet.of(ProcEffect.Trigger.WHITE, ProcEffect.Trigger.YELLOW,
        		ProcEffect.Trigger.WHITECRIT, ProcEffect.Trigger.YELLOWCRIT);
        p.rate = 0.10;
        p.buffDuration = 10;
        p.buffCooldown = 50;
        p.set(Effect.CRIT_RATING, 2178);
        procs.registerProcByItemID(65140, p);

        // Spells
        p = new ProcEffect();
        p.name = "Synapse Springs";
        p.triggers = EnumSet.of(ProcEffect.Trigger.USER);
        p.set(Effect.AGILITY, 480);
        p.buffDuration = 10;
        p.buffCooldown = 60;
        p.buffLinkedCooldown = 10;
        procs.registerProcBySpellID(82175, p);

        p = new ProcEffect();
        p.name = "Hand-Mounted Pyro Rocket";
        p.triggers = EnumSet.of(ProcEffect.Trigger.USER);
        p.set(Effect.SPELL_DAMAGE, (1654 + 2020) / 2);
        p.buffCooldown = 45;
        p.buffLinkedCooldown = 10;
        procs.registerProcBySpellID(54998, p);

        // Potions
        p = new ProcEffect();
        p.name = "Potion of Speed";
        p.triggers = EnumSet.of(ProcEffect.Trigger.POTION);
        p.set(Effect.HASTE_RATING, 500);
        p.buffDuration = 15;
        procs.registerProcByPotionID(40211, p);

        p = new ProcEffect();
        p.name = "Potion of the Tol'vir";
        p.triggers = EnumSet.of(ProcEffect.Trigger.POTION);
        p.set(Effect.AGILITY, 1200);
        p.buffDuration = 25;
        procs.registerProcByPotionID(80495, p);
    }

    /**
     * Calculate DPS and relative stat values.
     */
    public void generateEPValues() {
        Report result;

        Toon baseDruid = new PropertiesToonBuilder().setConfig(mConfig).build();
        Target target = new Target(mConfig, baseDruid);
        System.out.println(baseDruid);
        Properties stats;

        int statScale;
		try {
			Class<?> c = Class.forName(mConfig.getProperties().getProperty("Mew.Class"));
			if (Formulation.class.isAssignableFrom(c)) {
				statScale = 1;
			} else if (Simulation.class.isAssignableFrom(c)) {
				statScale = 100; // XXX: This should be configurable;
			} else throw new RuntimeException();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return;
		}

		if (mShouldOptimize) {
			ArrayList<CandidateStat> candidateStats = new ArrayList<CandidateStat>();
//			candidateStats.add(CandidateStat.SPIRIT);
//			candidateStats.add(CandidateStat.PARRY_RATING);
//			candidateStats.add(CandidateStat.DODGE_RATING);
			candidateStats.add(CandidateStat.CRIT_RATING);
			candidateStats.add(CandidateStat.HASTE_RATING);
			candidateStats.add(CandidateStat.MASTERY_RATING);
			candidateStats.add(CandidateStat.HIT_RATING);
			candidateStats.add(CandidateStat.EXPERTISE_RATING);

			Optimizer optimizer = new Optimizer();
//			result = optimizer.compute(mew, baseDruid, target, mConfig, Stat.MITIGATION_VALUE, candidateStats);
			result = optimizer.compute(mew, baseDruid, target, mConfig, Stat.DAMAGE_DEALT_PER_SECOND, candidateStats);

			System.out.println(result.getLog());

			return;
		}

        // Calculate the base DPS.
        double baseDPS = 0, baseError;
        long start = System.nanoTime();
        if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
            return;
        }
        double elapsed = (double)(System.nanoTime() - start) / 1000000000.0;
        baseDPS = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean();
        baseError = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError();

        shouldPrintLog = false;

        System.out.println(result);

        if (result.getLog() != null) {
        	System.out.println();
        	System.out.println(result.getLog());
        	System.out.println();
        }

        System.out.println("Base DPS: " + baseDPS + " ±" + baseError * 1.96);
        System.out.println("Standard Deviation " + result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardDeviation());
        System.out.println("Time taken: " + elapsed + " seconds");
        System.out.println();

        if (!mShouldGenerateRSV) return;

		//
		// Generate relative stat values now.
		//
		StatLogic statLogic = StatLogic.get(baseDruid.level, Clazz.DRUID);
		int targetLevel = target.getLevel();

		// Calculate Strength DPS.
//		double strengthDPS = 0;
//		baseDruid.strength += statScale;
//		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
//			return;
//		}
//		baseDruid.strength -= statScale;
//		strengthDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
//		double strengthError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Calculate Agility DPS.
		double agilityDPS = 0;
		baseDruid.agility += statScale;
		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
			return;
		}
		baseDruid.agility -= statScale;
		agilityDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double agilityError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Calculate AP DPS.
		double apDPS = 0;
		baseDruid.attackPower += statScale;
		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
			return;
		}
		baseDruid.attackPower -= statScale;
		apDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double apError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Derive Strength DPS.
		double strengthDPS = apDPS * (mConfig.getProperties().getProperty("Buff.StatMult", "false").equals("true") ? 1.05: 1);
		double strengthError = apError;

		// Calculate Haste rating DPS.
		double hasteDPS = 0;
		baseDruid.hasteRating += statScale;
		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
			return;
		}
		baseDruid.hasteRating -= statScale;
		hasteDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double hasteError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Calculate Crit rating DPS.
		double critDPS = 0;
		baseDruid.critRating += statScale;
		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
			return;
		}
		baseDruid.critRating -= statScale;
		critDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double critError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Calculate Mastery rating DPS.
		double masteryDPS = 0;
		baseDruid.masteryRating += statScale;
		if ((result = mew.compute(baseDruid, target, mConfig)) == null) {
			return;
		}
		baseDruid.masteryRating -= statScale;
		masteryDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double masteryError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

		// Calculate Hit rating DPS.
		double hitDPS = 0, hitError;
		stats = mConfig.copyProperties();
		double hitDPSHigh = 0;

		stats.setProperty("HitRating", Integer.toString(statLogic.getMeleeSpecialHitRatingCap(targetLevel)));
		if ((result = mew.compute(new PropertiesToonBuilder().setProperties(stats).build(), target, mConfig)) == null) {
			return;
		}
		hitDPSHigh = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean();
		double hitErrorHigh = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError();

		double hitDPSLow = 0;
		stats.setProperty("HitRating", Integer.toString(0));
		if ((result = mew.compute(new PropertiesToonBuilder().setProperties(stats).build(), target, mConfig)) == null) {
			return;
		}
		hitDPSLow = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean();
		double hitErrorLow = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError();

		hitDPS = (hitDPSHigh - hitDPSLow) / statLogic.getMeleeSpecialHitRatingCap(targetLevel);
		hitError = propogateDiffError(hitErrorHigh, hitErrorLow) / statLogic.getMeleeSpecialHitRatingCap(targetLevel);

		// Calculate Expertise DPS.
		double expertiseDPS = 0, expertiseError;
		stats = mConfig.copyProperties();
		double expertiseDPSHigh = 0;

		stats.setProperty("ExpertiseRating", Integer.toString(statLogic.getExpertiseRatingSoftCap(targetLevel)));
		if ((result = mew.compute(new PropertiesToonBuilder().setProperties(stats).build(), target, mConfig)) == null) {
			return;
		}
		expertiseDPSHigh = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean();
		double expertiseErrorHigh = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError();

		double expertiseDPSLow = 0;
		stats.setProperty("ExpertiseRating", Integer.toString(statLogic.getExpertiseRatingSoftCap(targetLevel) - statScale));
		if ((result = mew.compute(new PropertiesToonBuilder().setProperties(stats).build(), target, mConfig)) == null) {
			return;
		}
		expertiseDPSLow = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean();
		double expertiseErrorLow = result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError();

		expertiseDPS = (expertiseDPSHigh - expertiseDPSLow) / statLogic.getExpertiseRatingSoftCap(targetLevel);
		expertiseError = propogateDiffError(expertiseErrorHigh, expertiseErrorLow) / statLogic.getExpertiseRatingSoftCap(targetLevel);

		// Calculate Weapon DPS.
		double weaponDPS = 0;
		stats = mConfig.copyProperties();
		double weaponSpeed = baseDruid.weaponSpeed / 1000;
		stats.setProperty("WeaponTop", Integer.toString((int) Math.floor(baseDruid.weaponTop + statScale * weaponSpeed)));
		stats.setProperty("WeaponBottom", Integer.toString((int) Math.floor(baseDruid.weaponBottom + statScale * weaponSpeed)));
		if ((result = mew.compute(new PropertiesToonBuilder().setProperties(stats).build(), target, mConfig)) == null) {
			return;
		}
		weaponDPS = (result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean() - baseDPS) / statScale;
		double weaponError = propogateDiffError(baseError, result.getResult(Stat.DAMAGE_DEALT_PER_SECOND).getStandardError()) / statScale;

        System.out.println("Strength:DPS = " + strengthDPS + " ±" + strengthError * 1.96);
        System.out.println("Agility:DPS = " + agilityDPS + " ±" + agilityError * 1.96);
        System.out.println("Attack Power:DPS = " + apDPS + " ±" + apError * 1.96);
        System.out.println("Haste Rating:DPS = " + hasteDPS + " ±" + hasteError * 1.96);
        System.out.println("Crit Rating:DPS = " + critDPS + " ±" + critError * 1.96);
        System.out.println("Mastery Rating:DPS = " + masteryDPS + " ±" + masteryError * 1.96);
        System.out.println("Hit Rating:DPS = " + hitDPS + " ±" + hitError * 1.96);
        System.out.println("Expertise Rating:DPS = " + expertiseDPS + " ±" + expertiseError * 1.96);
        System.out.println("Weapon DPS:DPS = " + weaponDPS + " ±" + weaponError * 1.96);
    }

    private double propogateDiffError(double a, double b) {
    	return Math.sqrt(a*a + b*b);
    }

    public static void main(String args[]) {
        MewCommandLine mewCommandLine = new MewCommandLine();

        mewCommandLine.mew = new Mew(mewCommandLine);

        System.out.println("Mew - Cataclysm Feral DPS Calculator");
        System.out.println("Yawning <yawninglol at gmail.com>");
        System.out.println("");

        if(args.length != 1) {
            System.out.println("ERROR: You must specify a config file to use.");

            // XXX: This should go away eventually.
            System.out.println("WARNING: Using builtin default values instead.");
            System.out.println();

            mewCommandLine.loadFromFile("resources/SampleConfig.properties");
        } else if (mewCommandLine.loadFromFile(args[0]) == false) {
            System.out.println("ERROR: Failed to load config.  Aborting.");
            System.exit(-1);
        }

        mewCommandLine.generateEPValues();
    }
}
